MODULE ProcessorMod
   IMPLICIT NONE
   
   PRIVATE
   
   TYPE processor_Type
      INTEGER :: number
      INTEGER,POINTER,DIMENSION(:) :: grids
      INTEGER :: lastGrid
      !North=1,south=2,east=3,west=4
      INTEGER,DIMENSION(4) :: neighbour !
   END TYPE processor_Type
   TYPE(processor_Type),DIMENSION(:),ALLOCATABLE :: processor
   INTEGER :: maxProcessors
   INTEGER,PARAMETER :: pNorth=1,pSouth=2,pEast=3,pWest=4
   INTEGER,PARAMETER :: error=0
   
   PUBLIC createProcessor,getNumber,destroyProcessor,setNumber,addGrid,getGrid,getLastGrid
   PUBLIC findGrids, removeGrids,pNorth,pSouth,pEast,pWest,setNeighbour,getPNeighbour
   PUBLIC getMaxProcessors,dumpNeighbour
   
   CONTAINS
   
   INTEGER FUNCTION createProcessor(nprocessors)
      INTEGER,INTENT(IN) :: nprocessors
      
      INTEGER :: i,j
      
      IF(allocated(processor)) THEN
         createProcessor=error
      ELSE
         ALLOCATE(processor(nprocessors))
         maxProcessors=nprocessors
	 DO i=1,nprocessors 
	    processor(i)%number=-1
	    processor(i)%lastGrid=0
	    DO j=1,4
	        processor(i)%neighbour(j)=0
	    END DO
	    IF(associated(processor(i)%grids)) nullify(processor(i)%grids)
	 END DO
         createProcessor=-1
      END IF
   END FUNCTION createProcessor

   INTEGER FUNCTION destroyProcessor()
      
      IF(.not. allocated(Processor)) THEN
         destroyProcessor=error
      ELSE
         DEALLOCATE(Processor)
         maxProcessors=0
         destroyProcessor=-1
      END IF
      
   END FUNCTION destroyProcessor

   INTEGER FUNCTION setNeighbour(nProcessor,neig,direction)
      INTEGER, INTENT(IN) :: nProcessor,neig,direction
      
      IF(.not. allocated(processor) .or. nProcessor>maxProcessors .or. neig>maxProcessors .or. direction<1 .or. direction>4) THEN
         setNeighbour=error
      ELSE
         processor(nProcessor)%neighbour(direction)=neig
	 setNeighbour=-1
      END IF
   END FUNCTION setNeighbour
   
   INTEGER FUNCTION getPNeighbour(nProcessor,direction)
      INTEGER, INTENT(IN) :: nProcessor,direction
      
      IF(.not. allocated(processor) .or. nProcessor>maxProcessors .or. direction<pNorth .or. direction>pWest) THEN
         getPNeighbour=-1
      ELSE
         getPNeighbour=processor(nProcessor)%neighbour(direction)
      END IF
   END FUNCTION getPNeighbour
   
   INTEGER FUNCTION getNumber(nprocessor)
      INTEGER,INTENT(IN) :: nprocessor
      
      IF(.not. allocated(processor) .or. nProcessor>maxProcessors) THEN
        getNumber=-1
      ELSE
        getNumber=processor(nprocessor)%number
      END IF
   
   END FUNCTION getNumber

   INTEGER FUNCTION setNumber(nprocessor,num)
      INTEGER,INTENT(IN) :: nprocessor,num
      
      IF(.not. allocated(processor) .or. nProcessor>maxProcessors) THEN
        setNumber=error
      ELSE
        processor(nprocessor)%number=num
	setNumber=-1
      END IF
   
   END FUNCTION setNumber
   
   INTEGER FUNCTION addGrid(ngrid,nProcessor)
      INTEGER, INTENT(IN) :: nProcessor
      INTEGER, INTENT(IN) ::ngrid
      
      INTEGER,ALLOCATABLE,DIMENSION(:) :: auxGrids !!!!!!!!
      INTEGER :: i
     
      IF(.not. allocated(processor) .or. nProcessor>maxProcessors) THEN
         addGrid=error
      ELSE
         IF(.not. associated(processor(nProcessor)%grids)) THEN
	    allocate(processor(nProcessor)%grids(1))
	    processor(nProcessor)%lastGrid=processor(nProcessor)%lastGrid+1
	    processor(nProcessor)%grids(processor(nProcessor)%lastGrid)=ngrid
	    addGrid=-1	    
	 ELSE
	    allocate(auxGrids(processor(nProcessor)%lastGrid))
	    DO i=1,processor(nProcessor)%lastGrid
	       	       auxgrids(i)=processor(nProcessor)%grids(i)
	    END DO
	    deallocate(processor(nProcessor)%grids)
	    processor(nProcessor)%lastGrid=processor(nProcessor)%lastGrid+1
	    ALLOCATE(processor(nProcessor)%grids(processor(nProcessor)%lastGrid))
	    DO i=1,processor(nProcessor)%lastGrid-1
	       processor(nProcessor)%grids(i)=auxgrids(i)
	    END DO
	    deallocate(auxGrids)
	    processor(nProcessor)%grids(processor(nProcessor)%lastGrid)=nGrid
	    addGrid=-1
	 END IF
      END IF
   END FUNCTION addGrid

   INTEGER FUNCTION getLastGrid(nProcessor)
      INTEGER,INTENT(IN) :: nProcessor
      
      IF(.not. allocated(processor) .or. nProcessor<0 .or. nProcessor>maxProcessors) THEN
         getLastGrid=-1
      ELSE
         getLastGrid=processor(nProcessor)%lastGrid
      END IF   
   END FUNCTION getLastGrid

   INTEGER FUNCTION getGrid(nprocessor,position)
      INTEGER, INTENT(IN) :: nprocessor
      INTEGER, INTENT(IN) :: position
      
      IF(position<0 .or. position>processor(nprocessor)%lastGrid .or. .not. allocated(processor) &
         .or. nprocessor>maxProcessors) THEN
         getGrid=-1
      ELSE
         getGrid=processor(nprocessor)%grids(position)
      END IF
   END FUNCTION getGrid
      
   INTEGER FUNCTION findGrids(ng,nprocessor)   
      INTEGER,INTENT(IN) :: ng,nProcessor
      
      INTEGER :: i

      IF(.not. allocated(processor) .or. .not. allocated(processor(nProcessor)%grids) .or. &
          nProcessor>maxProcessors) THEN
         findGrids=-1
      ELSE
         findGrids=0
	 DO i=1,processor(nProcessor)%lastGrid
	    IF(ng==processor(nProcessor)%grids(i)) THEN
	       findGrids=i
	       EXIT
	    END IF
	 END DO
     END IF
   END FUNCTION findGrids

   INTEGER FUNCTION removeGrids(position,nProcessor)
      INTEGER, INTENT(IN) :: position,nProcessor

      INTEGER,ALLOCATABLE,DIMENSION(:) :: auxgrids
      INTEGER :: i,k
      
      IF(.not. allocated(processor) .or. .not. allocated(processor(nprocessor)%grids) .or. &
          position<0 .or. position>processor(nprocessor)%lastgrid .or. nprocessor>maxProcessors) THEN
          removegrids=error
      ELSE
         ALLOCATE(auxgrids(processor(nprocessor)%lastgrid))
	 DO i=1,processor(nprocessor)%lastgrid
	    auxgrids(i)=processor(nprocessor)%grids(i)
	 END DO
	 deallocate(processor(nprocessor)%grids)
	 processor(nprocessor)%lastgrid=processor(nprocessor)%lastgrid-1
	 ALLOCATE(processor(nprocessor)%grids(processor(nprocessor)%lastgrid))
	 k=0
	 DO i=1,processor(nprocessor)%lastgrid+1	 
	    IF(i/=position) THEN
	       k=k+1
	       processor(nprocessor)%grids(k)=auxgrids(i)
	    END IF
         END DO
         removegrids=-1
	 DEALLOCATE(auxgrids)
      END IF
      
   END FUNCTION removeGrids

   INTEGER FUNCTION getMaxProcessors()
     
     getMaxProcessors=maxProcessors
   
   END FUNCTION getMaxProcessors
   
   SUBROUTINE dumpNeighbour()
   
      INTEGER :: p
      WRITE (*,FMT='(A)') '=========================================='
      WRITE (*,FMT='(A5,1X,5(A3,1X))') 'Proc.',' N ',' S ',' E ',' W '
      DO p=1,maxProcessors
          WRITE (*,FMT='(I5.5,1X,5(I3.3,1X))') p,processor(p)%neighbour(1), &
	               processor(p)%neighbour(2), &
	               processor(p)%neighbour(3), &
	               processor(p)%neighbour(4)
      END DO	         
      
   END SUBROUTINE dumpNeighbour
   
END MODULE ProcessorMod
